package com.imooc.order.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.order.dao.OrderDetailDao;
import com.imooc.order.dto.OrderMessageDTO;
import com.imooc.order.enummeration.OrderStatus;
import com.imooc.order.po.OrderDetailPO;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * ProjectName order
 * 处理受到消息之后的操作
 *
 * @author xieyucan
 * <br>CreateDate 2022/9/20 13:46
 */
@Slf4j
@Service
public class OrderMessageService {

    ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OrderDetailDao orderDetailDao;


    /**
     * 声明消息队列、交换机、绑定、消息的处理
     */
    @Async
    public void handleMessage() throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("43.138.244.235");
        connectionFactory.setPort(5672);
        connectionFactory.setPassword("1234");
        connectionFactory.setUsername("admin");

        try (Connection connection = connectionFactory.newConnection();
             Channel channel = connection.createChannel()) {

            /*----------------------restaurant-----------------------*/
            channel.exchangeDeclare(
                    "exchange.order.restaurant",
                    BuiltinExchangeType.DIRECT,
                    true,
                    false,
                    null);
            channel.queueDeclare(
                    "queue.order",
                    true,
                    false,
                    false,
                    null);
            channel.queueBind("queue.order",
                    "exchange.order.restaurant",
                    "key.order");

            /*----------------------deliveryman-----------------------*/
            channel.exchangeDeclare(
                    "exchange.order.deliveryman",
                    BuiltinExchangeType.DIRECT,
                    true,
                    false,
                    null);
            channel.queueBind("queue.order",
                    "exchange.order.deliveryman",
                    "key.order");
            /*----------------------settlement-----------------------*/
            channel.exchangeDeclare(
                    "exchange.settlement.order",
                    BuiltinExchangeType.FANOUT,
                    true,
                    false,
                    null);
            channel.queueBind("queue.order",
                    "exchange.settlement.order",
                    "key.order");

            /*----------------------reward-----------------------*/
            channel.exchangeDeclare(
                    "exchange.order.reward",
                    BuiltinExchangeType.TOPIC,
                    true,
                    false,
                    null);
            channel.queueBind("queue.order",
                    "exchange.order.reward",
                    "key.order");


            //去接收消息(注册了一个消费者对象)
            channel.basicConsume(
                    "queue.order",
                    true,
                    deliverCallback,
                    consumerTag -> {
                    }
            );
            while (true) {
                Thread.sleep(1000000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    DeliverCallback deliverCallback = ((consumerTag, message) -> {
        String messageBody = new String(message.getBody());
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("43.138.244.235");
        connectionFactory.setPort(5672);
        connectionFactory.setPassword("1234");
        connectionFactory.setUsername("admin");
        try {
            //将消息体反序列化成dto
            OrderMessageDTO orderMessageDTO = objectMapper.readValue(messageBody, OrderMessageDTO.class);
            //数据库中读取订单po
            OrderDetailPO orderDetailPO = orderDetailDao.selectOrder(orderMessageDTO.getOrderId());

            switch (orderDetailPO.getStatus()) {

                case ORDER_CREATING:
                    if (orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()) {
                        orderDetailPO.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
                        orderDetailPO.setPrice(orderMessageDTO.getPrice());
                        orderDetailDao.update(orderDetailPO);
                        //给骑手微服务发送消息
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            channel.basicPublish(
                                    "exchange.order.deliveryman",
                                    "key.deliveryman",
                                    null,
                                    messageToSend.getBytes()
                            );
                        }
                    } else {
                        orderDetailPO.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPO);
                    }
                    break;
                case RESTAURANT_CONFIRMED:
                    if (null != orderMessageDTO.getDeliverymanId()) {
                        orderDetailPO.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
                        orderDetailPO.setDeliverymanId(orderMessageDTO.getDeliverymanId());
                        orderDetailDao.update(orderDetailPO);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            channel.basicPublish(
                                    "exchange.order.settlement",
                                    "key.order",
                                    null,
                                    messageToSend.getBytes()
                            );
                        }
                    } else {
                        orderDetailPO.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPO);
                    }
                    break;
                case DELIVERYMAN_CONFIRMED:
                    if(orderMessageDTO.getSettlementId()!=null) {
                        orderDetailPO.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
                        orderDetailPO.setSettlementId(orderMessageDTO.getSettlementId());
                        orderDetailDao.update(orderDetailPO);
                        try(Connection connection = connectionFactory.newConnection();
                            Channel channel = connection.createChannel()){
                            String messageToSend=objectMapper.writeValueAsString(orderMessageDTO);
                            channel.basicPublish(
                                    "exchange.order.reward",
                                    "key.reward",
                                    null,
                                    messageToSend.getBytes()
                            );
                        }
                    } else {
                        orderDetailPO.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPO);
                    }
                    break;
                case SETTLEMENT_CONFIRMED:
                    if(orderMessageDTO.getRewardId()!=null) {
                        orderDetailPO.setStatus(OrderStatus.ORDER_CREATED);
                        orderDetailPO.setRewardId(orderMessageDTO.getRewardId());
                        orderDetailDao.update(orderDetailPO);
                    } else {
                        orderDetailPO.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPO);
                    }
                    break;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    });
}
